/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.sais.noisylibrary;

import java.awt.Color;
import org.sais.noisylibrary.card.AttributeCard;
import org.sais.noisylibrary.card.HelperCard;
import org.sais.noisylibrary.card.SpellCard;
import org.sais.noisylibrary.core.GameCore;
import org.sais.noisylibrary.core.Player;

/**
 *
 * @author Romulus
 */
public class IRCManager {

    public static final String[] COMMAND_PREFIX = new String[]{"#", "＃"};
    public static final String[] ORDER_PREFIX = new String[]{"！", "!"};
    private IRCWatchFrame mFrame;
    private IRCAgent mAgent;
    private IIRCManagerCallback mCaller;
    private String mChannel = null;
    private GameCore mCore;

    public IRCManager(IIRCManagerCallback caller) {
        mCaller = caller;
        mFrame = new IRCWatchFrame(this);
    }

    public void setAgent(IRCAgent agent) {
        mAgent = agent;
    }

    protected void onMessage(String channel, String sender, String login, String hostname, String message, boolean isNotice) {
        if (mChannel == null) {
            mChannel = channel;
        }

        int cmdprefix = isCommand(message);
        if (cmdprefix > 0) {
            mFrame.showMessage("<" + sender + "> " + message, new Color(0, 100, 0));
            dispatchCommand(channel, sender, login, hostname, message.substring(cmdprefix));
            return;
        }

        cmdprefix = isOrder(message);
        if (cmdprefix > 0) {
            mFrame.showMessage("<" + sender + "> " + message, new Color(100, 100, 0));
            dispatchOrder(channel, sender, login, hostname, message.substring(cmdprefix));
            return;
        }

        if (isNotice) {
            mFrame.showMessage("<" + sender + "> " + message, Color.RED);
        } else {
            mFrame.showMessage("<" + sender + "> " + message);
        }
    }

    private void dispatchCommand(String channel, String sender, String login, String hostname, String command) {
        command = command.replace("　", " ");

        if (command.startsWith("参加")) {
            participate(sender);
            return;
        }
        if (command.startsWith("回収") || command.startsWith("取る") || command.startsWith("ゲット")) {
            acquire(deleteTailUnderline(sender), command);
            return;
        }
        if (command.startsWith("捨てる") || command.startsWith("破棄")) {
            discard(deleteTailUnderline(sender), command);
            return;
        }
        if (command.startsWith("ドロー")) {
            draw(deleteTailUnderline(sender));
            return;
        }
        if (command.startsWith("スペル戻し")) {
            returnSpell(deleteTailUnderline(sender), command);
            return;
        }
        if (command.startsWith("スペル強制")) {
            getSpellForced(deleteTailUnderline(sender), command);
            return;
        }
        if (command.startsWith("スペル譲渡")) {
            giveSpell(deleteTailUnderline(sender), command);
            return;
        }
        if (command.startsWith("スペル")) {
            getSpell(deleteTailUnderline(sender), command);
            return;
        }
        if (command.startsWith("渡す")) {
            giveAttr(deleteTailUnderline(sender), command);
            return;
        }
        if (command.startsWith("拾う")) {
            recycle(deleteTailUnderline(sender), command);
            return;
        }
        if (command.startsWith("隠して渡す")) {
            giveHelper(deleteTailUnderline(sender), command);
            return;
        }
        if (command.startsWith("公開")) {
            reveal(deleteTailUnderline(sender), command);
        }
        if (command.startsWith("場")) {
            showField();
            return;
        }
        if (command.startsWith("捨て場")) {
            showDiscarded();
            return;
        }
        if (command.startsWith("プレイヤー")) {
            showPlayers();
            return;
        }
        if (command.startsWith("助っ人")) {
            getHelper(sender, command);
            return;
        }
        if (command.startsWith("エンド")) {
            endTurn();
            return;
        }
    }

    private void dispatchOrder(String channel, String sender, String login, String hostname, String order) {
        order = order.replace("　", " ");

        if (order.startsWith("ゲーム準備")) {
            prepareGame();
            return;
        }
        if (order.startsWith("ゲーム開始")) {
            startGame();
            return;
        }
        if (order.startsWith("コマンド")) {
            sendSystemNotice(mChannel, "http://urakagij.blogspot.com/2010/01/irc.html");
            return;
        }
        if (order.startsWith("歴史喰い")) {
            eatHistory(order);
        }
        if (order.startsWith("テスト")) {
            prepareGame();
            participate(deleteTailUnderline(sender));
            participate(deleteTailUnderline(sender));
            startGame();
            return;
        }

    }

    // Order Handling
    private void prepareGame() {
        mCore = new GameCore();
        sendSystemNotice(mChannel, "準備が整ったわ。");
    }

    private void startGame() {
        sendSystemNotice(mChannel, "座順と初期状況をセットするわね。");
        mCore.decideOrder();
        mCore.dealInitialHand();
        sendSystemNotice(mChannel, "------------------------");
        int i = 1;
        for (Player p : mCore.getPlayers()) {
            sendSystemNotice(mChannel, i + ". " + p.getName() + " | " + p.getAttrHandString() + "|");
            ++i;
        }
        mCore.dealInitialField();
        showField();
        sendSystemNotice(mChannel, mCore.currentPlayer().getName() + "のターン、どうぞ？");
    }

    private void eatHistory(String order) {
        String[] ord = order.split(" ");
        if (ord.length < 2) {
            sendSystemNotice(mChannel, "「！歴史喰い　スペル」か「！歴史喰い　属性」でお願いね。");
            return;
        }
        mCore.eatHistory(ord[1]);
        sendSystemNotice(mChannel, "慧音先生に歴史を喰わせて頂いたわ。現在の場は以下の通りよ。");
        showField();
    }

    // End of Order Handling
    // Command Handling
    private void participate(String nick) {
        if (mCore.isGameStarted()) {
            sendSystemNotice(mChannel, nick + "ゲームはもう始まったわ。次のゲームを待ちなさい。");
            return;
        }
        nick = deleteTailUnderline(nick);
        if (nick == null) {
            sendSystemNotice(mChannel, "参加者のIDが不正よ。");
            return;
        }
        mCore.participate(nick);
        sendSystemNotice(mChannel, nick + "の参加を認めるわ。頑張ってね。");
    }

    private void acquire(String nick, String command) {
        String[] cmd = command.split(" ");
        if (cmd.length < 2) {
            sendSystemNotice(mChannel, "「＃回収　火」みたいなコマンドでお願いね。");
            return;
        }
        AttributeCard c = mCore.acquire(nick, cmd[1]);
        if (c != null) {
            sendSystemNotice(mChannel, nick + "が『" + c.toString() + "』を回収したわ。");
            sendSystemNotice(mChannel, nick + "の今の所持カードは『" + mCore.findPlayer(nick).getAttrHandString() + "』。");
            c = mCore.dealAttribute();
            sendSystemNotice(mChannel, "新しく場に置かれたカードは、『" + c.toString() + "』よ。");
        } else {
            sendSystemNotice(mChannel, "そんなカード無いわよ？・・・或いは非参加者の悪戯ね。");
        }
    }

    private void recycle(String nick, String command) {
        String[] cmd = command.split(" ");
        if (cmd.length < 2) {
            sendSystemNotice(mChannel, "「＃拾う　火」みたいなコマンドでお願いね。");
            return;
        }
        AttributeCard c = mCore.recycle(nick, cmd[1]);
        if (c != null) {
            sendSystemNotice(mChannel, nick + "が『" + c.toString() + "』を回収したわ。");
            sendSystemNotice(mChannel, nick + "の今の所持カードは『" + mCore.findPlayer(nick).getAttrHandString() + "』。");
        } else {
            sendSystemNotice(mChannel, "そんなカード無いわよ？・・・或いは非参加者の悪戯ね。");
        }
    }

    private void giveAttr(String nick, String command) {
        String[] cmd = command.split(" ");
        if (cmd.length < 3) {
            sendSystemNotice(mChannel, "「＃渡す　Pachouli　火」みたいなコマンドでお願いね。");
            return;
        }
        Player p = mCore.findPlayer(nick);
        Player r = mCore.findPlayer(cmd[1]);
        AttributeCard c = mCore.giveAttr(nick, deleteTailUnderline(cmd[1]), cmd[2]);
        if (c != null) {
            sendSystemNotice(mChannel, nick + "が『" + c.getName() + "』を" + r.getName() + "に渡したわ。");
            sendSystemNotice(mChannel, nick + "の残り属性は『" + p.getAttrHandString() + "』で、");
            sendSystemNotice(mChannel, r.getName() + "の所持属性は『" + r.getAttrHandString() + "』よ。");
        } else {
            sendSystemNotice(mChannel, "プレイヤー指定が間違ってるか、そのカードを持ってないわよ。");
        }
    }

    private void giveSpell(String nick, String command) {
        String[] cmd = command.split(" ");
        if (cmd.length < 3) {
            sendSystemNotice(mChannel, "「＃スペル譲渡　Pachouli　ヒマワリ」みたいなコマンドでお願いね。");
            return;
        }
        Player p = mCore.findPlayer(nick);
        Player r = mCore.findPlayer(cmd[1]);
        SpellCard c = mCore.giveSpell(nick, deleteTailUnderline(cmd[1]), cmd[2]);
        if (c != null) {
            sendSystemNotice(mChannel, nick + "が『" + c.getName() + "』を" + r.getName() + "に渡したわ。");
        } else {
            sendSystemNotice(mChannel, "プレイヤー指定が間違ってるか、そのカードを持ってないわよ。");
        }
    }

    private void giveHelper(String nick, String command) {
        String[] cmd = command.split(" ");
        if (cmd.length < 2) {
            sendSystemNotice(mChannel, "「＃隠して渡す　Pachuouli」みたいなコマンドでお願いね。");
            return;
        }
        Player p = mCore.findPlayer(nick);
        Player r = mCore.findPlayer(cmd[1]);
        HelperCard c = mCore.giveHelper(nick, deleteTailUnderline(cmd[1]));
        if (c != null) {
            mAgent.sendMessage(cmd[1], "あなたが引いたカードは『" + c.getName() + "』、");
            mAgent.sendMessage(cmd[1], "効果は『" + c.getEffect() + "』よ。");
            if (c.getPoint() > 0) {
                mAgent.sendMessage(cmd[1], "更に、このカードは " + c.getPoint() + " 点として扱うことも出来るわ。");
            }
            sendSystemNotice(mChannel, nick + "が助っ人カードを" + r.getName() + "に渡したわ。");
        } else {
            sendSystemNotice(mChannel, "プレイヤー指定が間違ってるか、助っ人を持ってないわよ。渡すプレイヤーIDはアンダーラインも必要よ？");
        }
    }

    private void returnSpell(String nick, String command) {
        String[] cmd = command.split(" ");
        if (cmd.length < 2) {
            sendSystemNotice(mChannel, "「＃スペル戻し　ヒマワリ」みたいなコマンドでお願いね。");
            return;
        }
        Player p = mCore.findPlayer(nick);
        SpellCard c = mCore.returnSpell(nick, deleteTailUnderline(cmd[1]));
        if (c != null) {
            sendSystemNotice(mChannel, nick + "が『" + c.getName() + "』を山札の下の戻したわ。");
        } else {
            sendSystemNotice(mChannel, "プレイヤー指定が間違ってるか、そのカードを持ってないわよ。");
        }
    }

    private void getSpell(String nick, String command) {
        String[] cmd = command.split(" ");
        if (cmd.length < 2) {
            sendSystemNotice(mChannel, "「＃スペル　日符」「＃スペル　ロイヤルフレア」みたいなコマンドでお願いね。");
            return;
        }
        SpellCard c = mCore.getSpell(nick, cmd[1]);
        Player p = mCore.findPlayer(nick);
        if (c != null) {
            sendSystemNotice(mChannel, nick + "が『" + c.getName() + "』をゲットしたわ。これで " + p.currentPoints() + " 点ね。");
            sendSystemNotice(mChannel, nick + "の残り属性カードは『" + p.getAttrHandString() + "』で、");
            c = mCore.dealSpell();
            sendSystemNotice(mChannel, "新しく場に置かれたカードは、『" + c.toString() + "』よ。");
            sendSystemNotice(mChannel, "新しい状況カードは、『" + mCore.getSituationCard().getName() + "』。");
            sendSystemNotice(mChannel, "効果は『" + mCore.getSituationCard().getEffect() + "』だわ。");
        } else {
            sendSystemNotice(mChannel, "ダメダメ。そんなスペル出してないか、属性カードが足りないわよ。");
        }
    }

    private void getSpellForced(String nick, String command) {
        String[] cmd = command.split(" ");
        if (cmd.length < 2) {
            sendSystemNotice(mChannel, "「＃スペル強制　日符」「＃スペル強制　ロイヤルフレア」みたいなコマンドでお願いね。");
            return;
        }
        SpellCard c = mCore.getSpellForced(nick, cmd[1]);
        Player p = mCore.findPlayer(nick);
        if (c != null) {
            sendSystemNotice(mChannel, nick + "が『" + c.getName() + "』をゲットしたわ。これで " + p.currentPoints() + " 点ね。");
            sendSystemNotice(mChannel, nick + "の残り属性カードは『" + p.getAttrHandString() + "』で、");
            c = mCore.dealSpell();
            sendSystemNotice(mChannel, "新しく場に置かれたカードは、『" + c.toString() + "』よ。");
            sendSystemNotice(mChannel, "新しい状況カードは、『" + mCore.getSituationCard().getName() + "』。");
            sendSystemNotice(mChannel, "効果は『" + mCore.getSituationCard().getEffect() + "』だわ。");
        } else {
            sendSystemNotice(mChannel, "ダメダメ。そんなスペル出してないか、属性カードが足りないわよ。");
        }
    }

    private void showField() {
        sendSystemNotice(mChannel, "------------------------");
        sendSystemNotice(mChannel, "場の属性カード：" + mCore.getAttrFieldString());
        sendSystemNotice(mChannel, "状況カード：" + (mCore.getSituationCard() == null ? "なし" : mCore.getSituationCard().getName()));
        sendSystemNotice(mChannel, "------------------------");
        for (String s : mCore.getSpellFieldStrings()) {
            sendSystemNotice(mChannel, s);
        }
        sendSystemNotice(mChannel, "------------------------");
    }

    private void showDiscarded() {
        sendSystemNotice(mChannel, "捨て札にある属性カードは『" + mCore.getAttrConsumedString() + "』よ。");
    }

    private void showPlayers() {
        for (Player p : mCore.getPlayers()) {
            sendSystemNotice(mChannel, p.getName() + "　" + p.currentPoints() + "点　助っ人" + (p.hasHelper() ? "あり" : "なし") + " "
                    + p.getAttrHandString());
            for (SpellCard c : p.getSpellHand()) {
                sendSystemNotice(mChannel, c.toString());
            }
        }
    }

    private void endTurn() {
        mCore.nextTurn();
        Player p = mCore.currentPlayer();
        sendSystemNotice(mChannel, p.getName() + "のターン。所持カードは『" + p.getAttrHandString() + "』");
        sendSystemNotice(mChannel, "場の属性カードは『" + mCore.getAttrFieldString() + "』ね。");
    }

    private void discard(String nick, String command) {
        String[] cmd = command.split(" ");
        if (cmd.length < 2) {
            sendSystemNotice(mChannel, "「＃破棄　金」みたいなコマンドでお願いね。");
            return;
        }
        AttributeCard c = mCore.discard(nick, cmd[1]);
        if (c != null) {
            sendSystemNotice(mChannel, nick + "が『" + c.toString() + "』を破棄したわ。");
            sendSystemNotice(mChannel, nick + "の今の所持カードは『" + mCore.findPlayer(nick).getAttrHandString() + "』よ。");
        } else {
            sendSystemNotice(mChannel, "そんなカード持っていないわよ？");
        }
    }

    private void draw(String nick) {
        AttributeCard c = mCore.draw(nick);
        sendSystemNotice(mChannel, nick + "が『" + c.toString() + "』を引いたよ。");
        sendSystemNotice(mChannel, nick + "の今の所持カードは『" + mCore.findPlayer(nick).getAttrHandString() + "』。");
    }

    private void getHelper(String nick, String command) {
        String[] cmd = command.split(" ");
        if (cmd.length < 3) {
            sendSystemNotice(mChannel, "「＃助っ人　土　木」みたいなコマンドでお願いね。");
            return;
        }
        HelperCard c = mCore.getHelper(deleteTailUnderline(nick), cmd);
        if (c != null) {
            mAgent.sendMessage(nick, "あなたが引いたカードは『" + c.getName() + "』、");
            mAgent.sendMessage(nick, "効果は『" + c.getEffect() + "』よ。");
            if (c.getPoint() > 0) {
                mAgent.sendMessage(nick, "更に、このカードは " + c.getPoint() + " 点として扱うことも出来るわ。");
            }
            sendSystemNotice(mChannel, deleteTailUnderline(nick) + "が助っ人カードを入手したわ。");
            sendSystemNotice(mChannel, deleteTailUnderline(nick) + "の今の所持カードは『" + mCore.findPlayer(deleteTailUnderline(nick)).getAttrHandString() + "』。");
        } else {
            sendSystemNotice(mChannel, "属性が同じか、属性カードの指定が間違ってるわ。");
        }
    }

    private void reveal(String nick, String command) {
        HelperCard c = mCore.consumeHelper(nick, command.split(" "));
        if (c != null) {
            sendSystemNotice(mChannel, nick + "が助っ人カードを公開。『" + c.getName() + "』、");
            sendSystemNotice(mChannel, "効果は『" + c.getEffect() + "』よ。");
            if (c.getPoint() > 0) {
                sendSystemNotice(mChannel, "更に、" + c.getPoint() + "点として扱うことも出来るわ。");
            }
        } else {
            sendSystemNotice(mChannel, "指定された助っ人カードは無いわ。");
        }
    }

    // End of Command Handling
    private static String deleteTailUnderline(String string) {
        try {
            while (string.endsWith("_")) {
                string = string.substring(0, string.length() - 1);
            }
            return string;
        } catch (Exception e) {
            return null;
        }
    }

    private void showSystemMessage(String message) {
        mFrame.showMessage(message, new Color(0, 100, 140));
    }

    private void sendSystemMessage(String channel, String message) {
        mAgent.sendMessage(channel, message);
    }

    private void sendSystemNotice(String channel, String message) {
        mAgent.sendNotice(channel, message);
    }

    /**
     * Check if the message is a command.
     * @param message
     * @return the length of prefix. 0 if the message is not a command.
     */
    private int isCommand(String message) {
        for (String s : COMMAND_PREFIX) {
            if (message.startsWith(s)) {
                return s.length();
            }
        }
        return 0;
    }

    private int isOrder(String message) {
        for (String s : ORDER_PREFIX) {
            if (message.startsWith(s)) {
                return s.length();
            }
        }
        return 0;
    }
}
